package com.sliface.web.core;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import org.objectweb.asm.*;

public class MethodInvokerImplDump implements Opcodes {
	
	public static void main(String[] args){
		try {
			byte[] raw = dump();
			BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream(new File("./build/war/WEB-INF/classes/com/sliface/web/core/MethodInvoker.class")));
			bw.write(raw);
			bw.flush();
			bw.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static byte[] dump () throws Exception {


		ClassWriter cw = new ClassWriter(0);
		FieldVisitor fv;
		MethodVisitor mv;
		AnnotationVisitor av0;

		cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "com/sliface/web/core/MethodInvoker", null, "java/lang/Object", null);

		cw.visitSource("MethodInvoker.java", null);

		{
		fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, "instance", "Lcom/sliface/web/core/MethodInvoker;", null, null);
		fv.visitEnd();
		}
		{
		fv = cw.visitField(0, "facade", "Lcom/sliface/web/app/Facade;", null, null);
		fv.visitEnd();
		}
		{
		mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
		mv.visitCode();
		Label l0 = new Label();
		mv.visitLabel(l0);
		mv.visitLineNumber(12, l0);
		mv.visitInsn(ACONST_NULL);
		mv.visitFieldInsn(PUTSTATIC, "com/sliface/web/core/MethodInvoker", "instance", "Lcom/sliface/web/core/MethodInvoker;");
		Label l1 = new Label();
		mv.visitLabel(l1);
		mv.visitLineNumber(11, l1);
		mv.visitInsn(RETURN);
		mv.visitMaxs(1, 0);
		mv.visitEnd();
		}
		{
		mv = cw.visitMethod(ACC_PRIVATE, "<init>", "()V", null, null);
		mv.visitCode();
		Label l0 = new Label();
		mv.visitLabel(l0);
		mv.visitLineNumber(14, l0);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
		Label l1 = new Label();
		mv.visitLabel(l1);
		mv.visitLineNumber(13, l1);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitInsn(ACONST_NULL);
		mv.visitFieldInsn(PUTFIELD, "com/sliface/web/core/MethodInvoker", "facade", "Lcom/sliface/web/app/Facade;");
		Label l2 = new Label();
		mv.visitLabel(l2);
		mv.visitLineNumber(15, l2);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitMethodInsn(INVOKESTATIC, "com/sliface/web/app/Facade", "getInstance", "()Lcom/sliface/web/app/Facade;");
		mv.visitFieldInsn(PUTFIELD, "com/sliface/web/core/MethodInvoker", "facade", "Lcom/sliface/web/app/Facade;");
		Label l3 = new Label();
		mv.visitLabel(l3);
		mv.visitLineNumber(16, l3);
		mv.visitInsn(RETURN);
		Label l4 = new Label();
		mv.visitLabel(l4);
		mv.visitLocalVariable("this", "Lcom/sliface/web/core/MethodInvoker;", null, l0, l4, 0);
		mv.visitMaxs(2, 1);
		mv.visitEnd();
		}
		{
		mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "getInstance", "()Lcom/sliface/web/core/MethodInvoker;", null, null);
		mv.visitCode();
		Label l0 = new Label();
		mv.visitLabel(l0);
		mv.visitLineNumber(18, l0);
		mv.visitFieldInsn(GETSTATIC, "com/sliface/web/core/MethodInvoker", "instance", "Lcom/sliface/web/core/MethodInvoker;");
		Label l1 = new Label();
		mv.visitJumpInsn(IFNONNULL, l1);
		Label l2 = new Label();
		mv.visitLabel(l2);
		mv.visitLineNumber(19, l2);
		mv.visitTypeInsn(NEW, "com/sliface/web/core/MethodInvoker");
		mv.visitInsn(DUP);
		mv.visitMethodInsn(INVOKESPECIAL, "com/sliface/web/core/MethodInvoker", "<init>", "()V");
		mv.visitFieldInsn(PUTSTATIC, "com/sliface/web/core/MethodInvoker", "instance", "Lcom/sliface/web/core/MethodInvoker;");
		mv.visitLabel(l1);
		mv.visitLineNumber(21, l1);
		mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
		mv.visitFieldInsn(GETSTATIC, "com/sliface/web/core/MethodInvoker", "instance", "Lcom/sliface/web/core/MethodInvoker;");
		mv.visitInsn(ARETURN);
		mv.visitMaxs(2, 0);
		mv.visitEnd();
		}
		{
		MethodProfile[] methodProfileArray=FacadeProfile.extract();
		
		mv = cw.visitMethod(ACC_PUBLIC, "process", "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V", null, null);
		mv.visitCode();
		Label l0 = new Label();
		mv.visitLabel(l0);
		mv.visitLineNumber(29, l0);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletRequest", "getServletPath", "()Ljava/lang/String;");
		mv.visitVarInsn(ASTORE, 3);
		Label l1 = new Label();
		mv.visitLabel(l1);
		mv.visitLineNumber(30, l1);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitLdcInsn("targetPage");
		mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletRequest", "getParameter", "(Ljava/lang/String;)Ljava/lang/String;");
		mv.visitVarInsn(ASTORE, 4);
		Label l2 = new Label();
		mv.visitLabel(l2);
		mv.visitLineNumber(31, l2);
		mv.visitTypeInsn(NEW, "com/sliface/web/core/JsonParser");
		mv.visitInsn(DUP);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitLdcInsn("json");
		mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/http/HttpServletRequest", "getParameter", "(Ljava/lang/String;)Ljava/lang/String;");
		mv.visitMethodInsn(INVOKESPECIAL, "com/sliface/web/core/JsonParser", "<init>", "(Ljava/lang/String;)V");
		mv.visitVarInsn(ASTORE, 5);

		//extract the method profile
		Label[]  branchLableArray = new Label[methodProfileArray.length];
		for(int i=0 ;i<branchLableArray.length;i++){
			branchLableArray[i]=new Label();
		}
		int startLine = 31; 
		Label temp;
		Label returnLabel = new Label();
		for(int i=0 ;i<methodProfileArray.length;i++){
			mv.visitLabel(branchLableArray[i]);
			mv.visitLineNumber(++startLine, branchLableArray[i]);
			if(i==1){
				mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"java/lang/String", "java/lang/String"}, 0, null);
			}else if(i>1){
				mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
			}
			mv.visitVarInsn(ALOAD, 3);
			mv.visitLdcInsn("/"+methodProfileArray[i].MethodClassName+".do");
			mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z"); 
			if(i<methodProfileArray.length-1){
			    mv.visitJumpInsn(IFEQ, branchLableArray[i+1]);
			}else{
				mv.visitJumpInsn(IFEQ, returnLabel);
			}
			
			temp=new Label();
			mv.visitLabel(temp);
			mv.visitLineNumber(++startLine, temp);
			mv.visitVarInsn(ALOAD, 2);
			mv.visitVarInsn(ALOAD, 0);
			mv.visitFieldInsn(GETFIELD, "com/sliface/web/core/MethodInvoker", "facade", "Lcom/sliface/web/app/Facade;");
			String methodDesc="(";
			for(int j=0;j<methodProfileArray[i].getParamsClassNameArray().length;j++){
				mv.visitVarInsn(ALOAD, 5);
				mv.visitMethodInsn(INVOKEVIRTUAL, "com/sliface/web/core/JsonParser", "nextValue", "()Ljava/lang/String;");
				methodDesc=methodDesc+"L"+methodProfileArray[i].getParamsClassNameArray()[j].replace('.', '/')+";";
			}
			methodDesc=methodDesc+")"+"L"+methodProfileArray[i].getReturnValueClassName().replace('.', '/')+";";
			mv.visitMethodInsn(INVOKEVIRTUAL, "com/sliface/web/app/Facade", methodProfileArray[i].MethodClassName, methodDesc);
			mv.visitVarInsn(ALOAD, 4);
			mv.visitMethodInsn(INVOKESTATIC, "com/sliface/web/core/CommonFunction", "toJson", "(Ljavax/servlet/http/HttpServletResponse;Ljava/lang/Object;Ljava/lang/String;)V");
			if(i<methodProfileArray.length-1){
			    mv.visitJumpInsn(GOTO, returnLabel);
			}
		}
		startLine++;
		mv.visitLabel(returnLabel);
		mv.visitLineNumber(++startLine, returnLabel);
		mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
		mv.visitInsn(RETURN);
		Label lend = new Label();
		mv.visitLabel(lend);
		mv.visitLocalVariable("this", "Lcom/sliface/web/core/MethodInvoker;", null, l0, lend, 0);
		mv.visitLocalVariable("req", "Ljavax/servlet/http/HttpServletRequest;", null, l0, lend, 1);
		mv.visitLocalVariable("resp", "Ljavax/servlet/http/HttpServletResponse;", null, l0, lend, 2);
		mv.visitLocalVariable("method", "Ljava/lang/String;", null, l1, lend, 3);
		mv.visitLocalVariable("targetPage", "Ljava/lang/String;", null, l1, lend, 4);
		mv.visitLocalVariable("json", "Lcom/sliface/web/core/JsonParser;", null, l1, lend, 5);
		mv.visitMaxs(4, 6);
		mv.visitEnd();
		
		}
		cw.visitEnd();
		
		
		

		return cw.toByteArray();
		}
}
